import json
import re
from pydantic import BaseModel
from fastapi import APIRouter, Request
from utils import token_required
from music_tag.main import query_file, MUSIC_ROOT_DIR, add_play_count, query_lyrics, MusicProc
from music_tag.main import append as appendTag
from music_tag.main import remove as removeTag
from music_tag.main import query as queryTag

router = APIRouter()


class Song_List_model(BaseModel):
    play: str


class Update_Play_model(BaseModel):
    value: dict


class Opr_Music_model(BaseModel):
    value: str


class Query_Music_model(BaseModel):
    music: str


class Add_Play_Count_model(BaseModel):
    music: int


class Update_Virtual_Play_model(BaseModel):
    virtual: str
    name: str
    left: str
    opr: str
    right: str


class Update_Virtual_Play_Status_model(BaseModel):
    virtual: str
    status: bool


@router.get('/QueryPlayList')
def play_list_query():
    mp = MusicProc()
    play_list = mp.all_tags
    with open(f"{MUSIC_ROOT_DIR}/.play_list_filter.json", "r", encoding="utf-8") as f:
        play_list_filter = json.loads(f.read())
    for i in play_list_filter:
        if i in play_list and play_list_filter[i]:
            play_list.remove(i)
    play_li = []
    for i in list(play_list):
        play_li.append({"play": i, "nickname": ""})
    virtual_play = VirtualPlay().virtual_play
    for i in virtual_play:
        if not virtual_play[i]["status"]:
            continue
        play_li.append({"play": i, "nickname": virtual_play[i]["name"]})
    return {"playList": play_li}


@router.get('/QueryPlayListFilter')
def play_list_filter_query():
    with open(f"{MUSIC_ROOT_DIR}/.play_list_filter.json", "r", encoding="utf-8") as f:
        play_list_filter = json.loads(f.read())
    data = {}
    for i in MusicProc().all_tags:
        data[i] = False
    data.update(play_list_filter)
    with open(f"{MUSIC_ROOT_DIR}/.play_list_filter.json", "w", encoding="utf-8") as f:
        f.write(json.dumps(data, ensure_ascii=False, indent=4, sort_keys=True))
    data = sorted(data.items())
    data = dict(data)
    return {"playList": data}


@router.post('/UpdatePlayStatus')
@token_required
def play_update(data: Update_Play_model, req: Request):
    with open(f"{MUSIC_ROOT_DIR}/.play_list_filter.json", "r", encoding="utf-8") as f:
        play_list_filter = json.loads(f.read())
    for i in data.value:
        play_list_filter[i] = data.value[i]
    with open(f"{MUSIC_ROOT_DIR}/.play_list_filter.json", "w", encoding="utf-8") as f:
        f.write(json.dumps(play_list_filter, ensure_ascii=False, indent=4))
    return {"status": True}


@router.post('/TagOpr')
@token_required
def opr_music_tag(data: Opr_Music_model, req: Request):
    oprs = data.value.split("\n")
    for line in oprs:
        opr, ids, tag = line.replace("  ", " ").split(" ")
        sep_ids = []
        for item in re.findall(r'(\d+|\[\s*\d+\s*,\s*\d+\s*])', ids):
            if item.startswith('['):
                a, b = map(int, item[1:-1].split(','))
                sep_ids.extend(range(a, b + 1))
            else:
                sep_ids.append(int(item))
        ids = ",".join([str(i) for i in sep_ids])
        if opr == "a":
            for _id in ids.split(","):
                appendTag(_id, tag)
        elif opr == "d":
            removeTag(ids, tag)
        else:
            return {"status": False}
    return {"status": True}


@router.post('/MusicQuery')
def query_music(data: Query_Music_model):
    return {"data": queryTag("nd", data.music)}


@router.post('/PlayCountAdd')
def play_count_add(data: Add_Play_Count_model):
    add_play_count(data.music)
    return {"status": True}


@router.post('/LyricsQuery')
def lyrics_query(data: Add_Play_Count_model):
    return {"lyrics": query_lyrics(data.music)}


class VirtualPlay:
    def __init__(self):
        with open(f"{MUSIC_ROOT_DIR}/.virtual_play.json", "r", encoding="utf-8") as f:
            self.virtual_play = json.loads(f.read())

    def write(self):
        with open(f"{MUSIC_ROOT_DIR}/.virtual_play.json", "w", encoding="utf-8") as f:
            f.write(json.dumps(self.virtual_play, ensure_ascii=False))


def virtual_song_query(mp, vp, vplay):
    opr = vplay["opr"]
    if opr == "like":
        return mp.query_id_by_name(vplay["left"])
    left = set()
    if vplay["left"] in mp.all_tags:
        left = mp.query_id_by_tag(vplay["left"])
    elif vplay["left"] in vp.virtual_play:
        left = virtual_song_query(mp, vp, vp.virtual_play[vplay["left"]])
    else:
        li = vplay["left"].split(",")
        for i in li:
            if i != "":
                left.add(i)
    right = set()
    if vplay["right"] in mp.all_tags:
        right = mp.query_id_by_tag(vplay["right"])
    elif vplay["right"] in vp.virtual_play:
        right = virtual_song_query(mp, vp, vp.virtual_play[vplay["right"]])
    else:
        li = vplay["right"].split(",")
        for i in li:
            if i != "":
                try:
                    right.add(int(i))
                except Exception as err:
                    print(err)
    if opr == "and":
        return left & right
    elif opr == "or":
        return left | right
    elif opr == "sub":
        return left - right
    return set()


def song_list_query_by_tag(tag):
    mp = MusicProc()
    vp = VirtualPlay()
    if tag in mp.all_tags:
        return mp.query_file_by_tag(tag)
    elif tag in vp.virtual_play:
        ids = virtual_song_query(mp, vp, vp.virtual_play[tag])
        return mp.query_song_list_by_id(ids)
    return []


@router.post('/QuerySongList')
def song_list_query(data: Song_List_model):
    tag = data.play
    data = song_list_query_by_tag(tag)
    song_list = []
    for item in data:
        song_list.append({"id": item["id"], "name": f'{item["id"]}.{item["name"]}',  # "artist": "",
                          "url": f'{item["path"]}/{item["name"]}'})
    return {"songList": song_list}


@router.post('/VirtualPlayUpdate')
@token_required
def virtual_play_update(data: Update_Virtual_Play_model, req: Request):
    item = {
        "id": data.virtual,
        "name": data.name,
        "left": data.left,
        "opr": data.opr,
        "right": data.right
    }
    vp = VirtualPlay()
    if data.virtual == "":
        item["id"] = str(len(vp.virtual_play))
        item["status"] = True
    if item["id"] not in vp.virtual_play:
        vp.virtual_play[item["id"]] = item
    else:
        vp.virtual_play[item["id"]].update(item)
    vp.write()
    return {"status": True}


@router.post('/VirtualPlayStatusUpdate')
@token_required
def virtual_play_status_update(data: Update_Virtual_Play_Status_model, req: Request):
    vp = VirtualPlay()
    if data.virtual not in vp.virtual_play:
        return {"status": False}
    vp.virtual_play[data.virtual]["status"] = data.status
    vp.write()
    return {"status": True}


@router.get('/VirtualPlayQuery')
def virtual_play_query():
    vp = VirtualPlay()
    play_list = []
    for item in vp.virtual_play:
        play_list.append(vp.virtual_play[item])
    return {"virtualPlayList": play_list}


@router.post('/VirtualPlayRemove')
@token_required
def virtual_play_remove(data: Song_List_model, req: Request):
    vp = VirtualPlay()
    if data.play in vp.virtual_play:
        vp.virtual_play.pop(data.play)
    vp.write()
    return {"status": True}


if __name__ == '__main__':
    pass
